﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing.Drawing2D;

using iTextSharp.text;
using iTextSharp.text.pdf;
using PdfSharp;
using PdfSharp.Drawing;
using PdfSharp.Fonts;
using PdfSharp.Fonts.OpenType;

namespace iPdf
{
    /// <summary>
    /// A helper class for itextsharp related stuff
    /// </summary>
    class SharpHelper
    {
        public static void ClosePdf(Document document, PdfWriter writer, Stream outputStream,
                                        PdfReader reader, Stream inputStream, bool collectGarbage)
        {
            if (document != null)
            {
                document.Close();
            }

            if (writer != null)
            {
                writer.Close();
            }

            if (outputStream != null)
            {
                outputStream.Dispose();
            }

            if (reader != null)
            {
                reader.Close();
            }

            if (inputStream != null)
            {
                inputStream.Dispose();
            }

            if (collectGarbage)
            {
                Helper.CollectGarbage();
            }
        }

        public static void ClosePdf(PdfStamper stamper, Stream outputStream, PdfReader reader,
            Stream inputStream, bool collectGarbage)
        {
            if (stamper != null)
            {
                stamper.Close();
            }

            if (outputStream != null)
            {
                outputStream.Dispose();
            }

            if (reader != null)
            {
                reader.Close();
            }

            if (inputStream != null)
            {
                inputStream.Dispose();
            }

            if (collectGarbage)
            {
                Helper.CollectGarbage();
            }
        }

        public static void ClosePdf(Document document, PdfWriter writer, Stream outputStream,
                                        PdfReader reader, Stream inputStream)
        {
            ClosePdf(document, writer, outputStream, reader, inputStream, false);
        }

        public static void ClosePdf(Document document, PdfWriter writer, Stream outputStream)
        {
            ClosePdf(document, writer, outputStream, null, null);
        }

        public static void ClosePdf(PdfWriter writer, Stream outputStream)
        {
            ClosePdf(null, writer, outputStream);
        }

        public static void ClosePdf(PdfReader reader, Stream inputStream)
        {
            ClosePdf(null, null, null, reader, inputStream);
        }

        public static void ClosePdf(PdfStamper stamper, Stream outputStream,
                            PdfReader reader, Stream inputStream)
        {
            ClosePdf(stamper, outputStream, reader, inputStream, false);
        }

        public static Hashtable CreateBookmarkByPageNo(int pageNo, string title)
        {
            Hashtable bookmark = new Hashtable();
            bookmark["Action"] = "GoTo";
            string page = pageNo.ToString() + " FitV 0";
            bookmark["Page"] = page;
            bookmark["Title"] = title;
            return bookmark;
        }

        public static int GetNumberOfPagesOfPdfFile(string pdfFileName)
        {
            PdfReader reader = null;
            try
            {
                reader = new PdfReader(new RandomAccessFileOrArray(pdfFileName), null);
                int numberOfPages = reader.NumberOfPages;
                return numberOfPages;
            }
            catch
            {
                return 0;
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
            }
        }

        public static string GetPdfProperties(string fileName)
        {
            string fileProperties =  string.Empty;
            if ( !Helper.CheckExistsAndAccessible(fileName))
            {
                fileProperties += Helper.NewLine + global::iPdf.Properties.Resources.UnableToGetPropertyInfo;
                return fileProperties;
            }

            PdfReader reader ;
            try
            {
                reader = new PdfReader(new RandomAccessFileOrArray(fileName), null);
            }
            catch
            {
                fileProperties += Helper.NewLine + global::iPdf.Properties.Resources.UnableToGetPropertyInfo;
                return fileProperties;
            }

            string numOfPages =   Helper.NewLine + 
                                                global::iPdf.Properties.Resources.NumberOfPages + 
                                                reader.NumberOfPages.ToString();

            fileProperties += numOfPages;

            string fileSize = Helper.NewLine + global::iPdf.Properties.Resources.FileSize + 
                        Helper.GetFileSizeString(reader.FileLength);

            fileProperties += fileSize;

            if (reader.IsEncrypted())
            {
                fileProperties += Helper.NewLine + global::iPdf.Properties.Resources.Secured;
                int permissions = reader.Permissions;
                string permissionsVerbose = iTextSharp.text.pdf.PdfEncryptor.GetPermissionsVerbose(permissions);
                if(permissionsVerbose.Equals("Allowed:", StringComparison.OrdinalIgnoreCase))
                {
                    permissionsVerbose += " None";
                }
                                                    
                string permissionsInfo = Helper.NewLine +
                                            global::iPdf.Properties.Resources.PermissionsInfo +
                                            permissionsVerbose;
                fileProperties += permissionsInfo;
            }
            else
            {
                fileProperties += Helper.NewLine + global::iPdf.Properties.Resources.NotSecured;
            }

            int certifyLevel = reader.GetCertificationLevel();
            string certificationInfo = Helper.NewLine +
                            global::iPdf.Properties.Resources.CertifyLevel;
            switch (certifyLevel)
            {
                case PdfSignatureAppearance.NOT_CERTIFIED:
                    certificationInfo += global::iPdf.Properties.Resources.NotCertified;
                    break;

                case PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED:
                    certificationInfo += global::iPdf.Properties.Resources.NoChangesAllowed;
                    break;

                case PdfSignatureAppearance.CERTIFIED_FORM_FILLING:
                    certificationInfo += global::iPdf.Properties.Resources.FormFilling;
                    break;

                case PdfSignatureAppearance.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS:
                    certificationInfo += global::iPdf.Properties.Resources.FormFillingAndAnnotations;
                    break;
            }

            fileProperties += certificationInfo;

            string pdfVersion = Helper.NewLine +
                                global::iPdf.Properties.Resources.PdfVersion + reader.PdfVersion;
            fileProperties += pdfVersion;

            Hashtable info = reader.Info;
            foreach (DictionaryEntry entry in info)
            {
                string name = (string)entry.Key;
                string value = (string)entry.Value;
                if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value))
                {
                    fileProperties += Helper.NewLine + name + ": " + value;
                }
            }

            ClosePdf(reader, null);

            return fileProperties;
        }

        public static System.Drawing.SizeF RectangleToSizeF(Rectangle rect)
        {
            return new System.Drawing.SizeF(rect.Width, rect.Height);
        }

        public static void RegisterFontDirectory()
        {
            FontFactory.RegisterDirectory(Helper.SystemFontsDir);
        }

        public static void AddImageToXGraphics(
            XGraphics gfx, XImage image, TataLayout layout)
        {
             XMatrix transformationMatrix = layout.PerformLayoutOnPreviewPage(gfx.PageSize.ToSizeF(), 
                 image.Size.ToSizeF());
             gfx.MultiplyTransform(transformationMatrix);

             gfx.DrawImage(image, 0, 0);
        }

        public static void AddTextToXGraphics(
            XGraphics gfx, Text text, TataLayout layout)
        {
            XMatrix transformationMatrix = layout.PerformLayoutOnPreviewPage(gfx.PageSize.ToSizeF(),
                 text.Size.ToSizeF());
            gfx.MultiplyTransform(transformationMatrix);

            DrawTextToXGraphics(gfx, text);
        }

        public static void DrawTextToXGraphics(XGraphics gfx, Text text)
        {
            //create a brush with the text color
            XBrush brush = new XSolidBrush(text.Color);

            // Create a string format
            XStringFormat format = new XStringFormat();
            format.Alignment = XStringAlignment.Near;
            format.LineAlignment = XLineAlignment.Near;

            gfx.DrawString(text.String, text.Font, brush, 0, 0, format);
        }

        public static bool IsFontFamilyPdfSharpCompatible(System.Drawing.FontFamily gdiFontFamily)
        {
            try
            {
                int sampleFontSize = 10;
                XFont font = new XFont(gdiFontFamily.Name, sampleFontSize);
            }
            catch
            {
                return false;
            }

            return true;
        }

        public static void OptimizeMemoryUsage()
        {
            long memoryUsageThreshold = 1024 * 1024 * 150;
            long memoryUsage = GC.GetTotalMemory(false);

            if (memoryUsage >= memoryUsageThreshold)
            {
                FontDescriptorStock.Global.Clear();
                Helper.CollectGarbage();
            }
        }

        public static void UnpackFile(PdfReader reader, PdfDictionary fileSpec, string outPath)
        {
            if (fileSpec == null)
                return;
            PdfName type = (PdfName)PdfReader.GetPdfObject(fileSpec.Get(PdfName.TYPE));
            if (!PdfName.F.Equals(type) && !PdfName.FILESPEC.Equals(type))
                return;
            PdfDictionary ef = (PdfDictionary)PdfReader.GetPdfObject(fileSpec.Get(PdfName.EF));
            if (ef == null)
                return;
            PdfString fn = (PdfString)PdfReader.GetPdfObject(fileSpec.Get(PdfName.F));
            if (fn == null)
                return;
            FileInfo fLast = new FileInfo(fn.ToUnicodeString());
            string fullPath = Path.Combine(outPath, fLast.Name);
            if (File.Exists(fullPath))
                return;
            PRStream prs = (PRStream)PdfReader.GetPdfObject(ef.Get(PdfName.F));
            if (prs == null)
                return;
            byte[] bytes = PdfReader.GetStreamBytes(prs);

            if (!Directory.Exists(outPath))
            {
                Directory.CreateDirectory(outPath);
            }

            FileStream fout = Helper.OpenWrite(fullPath);
            fout.Write(bytes, 0, bytes.Length);
            fout.Close();
        }

    }
}
